﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using Danser_AJAXEnabledWebApplication.Faults;
using Danser_AJAXEnabledWebApplication.User_Controls;
using Danser_AJAXEnabledWebApplication.Resourses;
using Danser_Entity.Queries.Data;
using Danser_Entity.Queries.Filters;
using Danser_Entity.Entities;
using Danser_Entity.Utils;

namespace Danser_AJAXEnabledWebApplication
{
    /// <summary>
    /// Page to handle validation templates to execute when new test files are loaded to Danser system 
    /// </summary>
    public partial class DataValidationsNew : AbstractPage
    {
        #region Constants:

        //Session keys IDs
        private const String SESSION_NEWROW = "NewRow";
        private const String SESSION_VALIDATON_STRING = "ValidationString";
        private const String SESSION_COLUMNS_LIST = "DataValidationsNew.ColumnsList";
        private const String SESSION_EDITING_METHOD = "DataValidationsNew.EditingMethod";

        private const String ADD_METHOD = "Add";
        private const String MODIFY_METHOD = "Modify";

        //objectDataSource parameter IDs
        private const String ODS_NEWROW = "newRow";
        private const String ODS_FILTER_PARAMETER = "filter";

        //column control IDs
        private const String ROW_SELECTOR_ID = "rowSelector";
        private const String SAVE_ROW_BUTTON = "saveRowButton";
        private const String CANCEL_ROW_BUTTON = "cancelRowButton";
        private const String NAME_LABEL_ID = "nameLabel";
        private const String NAME_TEXTBOX_ID = "nameTextBox";
        private const String NAME_MODIFY_LABEL_ID = "displayNameOnModifyLabel";
        private const String APPLIED_LABEL_ID = "appliedOnDefaultLabel";
        private const String APPLIED_SELECTOR_ID = "appliedOnDefaultCheckBox";
        private const String MAIL_ERROR_MESSAGE_PANEL_ID = "errorMessagePanel";
        private const String MAIL_ERROR_MESSAGE_LABEL_ID = "errorMessageLabel";
        private const String MAILLIST_LABEL_ID = "mailistLabel";
        private const String MAILIST_LIST_ID = "mailListListBox";
        private const String RULE_LABEL_ID = "ruleLabel";
        private const String RULE_BUTTON_ID = "editRuleLinkButton";
        private const String RULE_MODIFY_LABEL_ID = "displayRuleOnModifyLabel";

        //Selected Tables for building the validation rule
        private readonly Groups[] SEARCHING_TABLES = new Groups[]
        {
            Groups.Information,
            Groups.Parameters,
            Groups.Results
        };

        //table names for filtering the Validation templates DataGrid
        private readonly Groups[] SEARCH_TABLE_NAME =
            new Groups[] 
            {
                Groups.ValidationTemplates
            };

        #endregion

        #region Page Load:

        /// <summary>
        /// loads the page...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void Page_Load(object sender, EventArgs e)
        {
            base.Page_Load(sender, e);

            //reset the warning message
            noRuleGeneratedPanel.Visible = false;

            if (!IsPostBack) //first time
            {
                //feed columns to list
                _pageFormatter.DisplayColumnsTemplate(dataGridView, columnsMultiSelectList, 1);
            }

            try
            {
                //to reset the parameter
                objectDataSource.SelectParameters[ODS_NEWROW].DefaultValue = "false";
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }
        }

        #endregion

        #region Filter Columns Pane:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void filterButton_Click(object sender, EventArgs e)
        {
            _pageFormatter.FilterColumnsByListSelection(dataGridView, columnsMultiSelectList);
        }

        #endregion

        #region Filter Rows Pane:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void filterValidationButton_Click(object sender, EventArgs e)
        {
            _pageFormatter.ToggleButtonText((Button)sender, new String[] { "Search Templates", "Hide Search" });

            validationsQueryPanel.Visible = !validationsQueryPanel.Visible;
            validationsQueryExpressionBuilder.setSearchingTables(SEARCH_TABLE_NAME);
            
            //set the expression builder to be in query mode
            validationsQueryExpressionBuilder.setBuilderMode(BuilderModes.BUILD_QUERY);
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void executeValidationQueryButton_Click(object sender, EventArgs e)
        {
            //get the conditions generated by the expression builder
            IList<Condition> conditions = validationsQueryExpressionBuilder.getConditions(true);

            if (conditions == null)
                return;

            //build a rule out of the conditions
            RuleExpression parsedRule = new RuleExpression(conditions);
            try
            {
                //when setting select parameter, SELECT method is automatically invoked
                objectDataSource.SelectParameters[ODS_FILTER_PARAMETER].DefaultValue =
                    parsedRule.ConditionsToString(true);
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }
        }

        #endregion 

        #region Select Buttons:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void selectAllButton_Click(object sender, EventArgs e)
        {
            if (dataGridView.EditIndex > -1)
                return;

            foreach (GridViewRow row in dataGridView.Rows)
            {
                CheckBox selector = row.FindControl(ROW_SELECTOR_ID) as CheckBox;
                if (selector != null)
                {
                    selector.Checked = true;
                }
            }
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void selectNoneButton_Click(object sender, EventArgs e)
        {
            if (dataGridView.EditIndex > -1)
                return;

            foreach (GridViewRow row in dataGridView.Rows)
            {
                CheckBox selector = row.FindControl(ROW_SELECTOR_ID) as CheckBox;
                if (selector != null)
                {
                    selector.Checked = false;
                }
            }
        }
        #endregion

        #region Rows Handling Buttons:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void addButton_Click(object sender, EventArgs e)
        {
            if (dataGridView.EditIndex > -1) //another row is already in edit mode
                return;

            //update editing mode in session
            Session[SESSION_EDITING_METHOD] = ADD_METHOD;

            try
            {
                //disable the filter pane
                DisableFilterPane();

                //save the configuration selected by the user
                SaveColumnsSelection();

                //show all columns for the adding
                DisplayAllGridColumns();

                //inserts an empty Item
                objectDataSource.Insert();

                //notify the SELECT method that there's a new row
                objectDataSource.SelectParameters[ODS_NEWROW].DefaultValue = "true";

                dataGridView.EditIndex = 0;
                Session[SESSION_NEWROW] = true;

                //set focus to first text box in row
                dataGridView.DataBind(); // update the rows count

                Page.SetFocus(((TextBox)dataGridView.Rows[dataGridView.EditIndex].FindControl(NAME_TEXTBOX_ID)));
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }
            
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void modifyButton_Click(object sender, EventArgs e)
        {

            if (dataGridView.EditIndex > -1) //another row is already in edit mode
                return;

            //update editing mode in session
            Session[SESSION_EDITING_METHOD] = MODIFY_METHOD;

            //disable the filter pane
            DisableFilterPane();

            //save the configuration selected by the user
            SaveColumnsSelection();

            //show all columns for the modifying
            DisplayAllGridColumns();

            objectDataSource.UpdateParameters["newRow"].DefaultValue = "false";

            try
            {
                //search for the first row seleced:
                for (int i = 0; i < dataGridView.Rows.Count; i++)
                {
                    CheckBox checkBox = dataGridView.Rows[i].FindControl(ROW_SELECTOR_ID) as CheckBox;
                    if (checkBox != null && checkBox.Checked)
                    {
                        //extract the save rule expression into the expressionBuilder
                        Label ruleString = dataGridView.Rows[i].FindControl(RULE_LABEL_ID) as Label;
                        expressionBuilder.DisplayRule(ruleString.Text);

                        dataGridView.EditIndex = i;
                        Session[SESSION_NEWROW] = false;

                        dataGridView.DataBind(); // to update grid's rows' mode

                        //set focus
                        Page.SetFocus(((TextBox)dataGridView.Rows[dataGridView.EditIndex].FindControl(NAME_TEXTBOX_ID)));
                        break;
                    }

                }
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }

        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void removeButton_Click(object sender, EventArgs e)
        {
            if (dataGridView.EditIndex > -1) //another row is already in edit mode
                return;

            IList<int> idsToDelete = new List<int>();

            //search for all the selected rows:
            for (int i = 0; i < dataGridView.Rows.Count; i++)
            {
                CheckBox checkBox = dataGridView.Rows[i].FindControl(ROW_SELECTOR_ID) as CheckBox;
                if (checkBox != null && checkBox.Checked)
                {
                    int idToDelete = (int)dataGridView.DataKeys[i].Value;
                    idsToDelete.Add(idToDelete);
                }
            }

            try
            {
                foreach (int index in idsToDelete)
                {
                    objectDataSource.DeleteParameters[0/*="ID"*/].DefaultValue = index.ToString();
                    objectDataSource.Delete();
                }
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }
        }

        #endregion

        #region Row Inner Buttons:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void saveRowButton_Click(object sender, EventArgs e)
        {
            int editIdx = dataGridView.EditIndex;

            if (editIdx < 0)
                return;

            //validate mail
            TextBox mailList = ((TextBox)dataGridView.Rows[editIdx].FindControl(MAILIST_LIST_ID));
            Panel messagePanel = ((Panel)dataGridView.Rows[editIdx].FindControl(MAIL_ERROR_MESSAGE_PANEL_ID));
            Label messageLabel = ((Label)dataGridView.Rows[editIdx].FindControl(MAIL_ERROR_MESSAGE_LABEL_ID));

            bool validMailList = Utils.isMailListValid(mailList.Text);
            messageLabel.Text = 
                validMailList ? 
                "" : 
                UIMessages.BadMailFormat;

            messagePanel.Visible = !String.IsNullOrEmpty(messageLabel.Text);

            if (!validMailList)
                return;

            try
            {
                if (Convert.ToBoolean(Session[SESSION_NEWROW]))
                {
                    //change location of row from first place to last
                    objectDataSource.UpdateParameters["newRow"].DefaultValue = "true";
                }

                dataGridView.UpdateRow(dataGridView.EditIndex, false);

                //hide the expression builder 
                expressionBuilder.Visible = false;
                expressionBuilder.ClearRule();

                //restore he selected configuration after saving row
                RestoreColumnsSelection();

                objectDataSource.SelectParameters[ODS_NEWROW].DefaultValue = "false";
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }

        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void cancelRowButton_Click(object sender, EventArgs e)
        {
            try
            {
                //delete the empty row added
                if (Convert.ToBoolean(Session[SESSION_NEWROW]))
                {
                    objectDataSource.DeleteParameters["newRow"].DefaultValue = "true";
                    dataGridView.DeleteRow(dataGridView.EditIndex);
                }
                //else - the row is in edit mode
                else if (dataGridView.EditIndex > -1)
                    dataGridView.EditIndex = -1;

                //hide the expression builder
                expressionBuilder.Visible = false;
                expressionBuilder.ClearRule();

                //restore he selected configuration after canceling execution
                RestoreColumnsSelection();

                objectDataSource.SelectParameters[ODS_NEWROW].DefaultValue = "false";
            }
            catch (Exception exception)
            {
                HandleGenericErrorPage(exception);
            }
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void editRuleLinkButton_Click(object sender, EventArgs e)
        {
            expressionBuilder.setSearchingTables(SEARCHING_TABLES);
            expressionBuilder.Visible = true;
        }

        #endregion

        #region DataGrid Handlers:

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void dataGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            string name = ((TextBox)dataGridView.Rows[e.RowIndex].FindControl(NAME_TEXTBOX_ID)).Text;
            bool appliedOnDefault = ((CheckBox)dataGridView.Rows[e.RowIndex].FindControl(APPLIED_SELECTOR_ID)).Checked;

            //create 1 long string out of the list items
            TextBox list = ((TextBox)dataGridView.Rows[e.RowIndex].FindControl(MAILIST_LIST_ID));

            String mailList = Utils.MergeArrayToString(getMailList(list.Text), ';');

            //import the rule string from the expression builder
            String validationRule = expressionBuilder.getRuleString();

            //display warning message in case of no rule generation
            noRuleGeneratedPanel.Visible = String.IsNullOrEmpty(validationRule);

            e.NewValues["name"] = name;
            e.NewValues["appliedOnDefault"] = appliedOnDefault.ToString();
            e.NewValues["mailList"] = mailList;
            e.NewValues["expression"] = validationRule;
        }

        /// <summary>
        /// event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void dataGridView_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridViewRow row = e.Row;
            if (row.RowType == DataControlRowType.DataRow)
            {
                //deal with the edited row
                if (row.RowIndex == dataGridView.EditIndex)
                {
                    //handle mail list column
                    TextBox mailList = row.FindControl(MAILIST_LIST_ID) as TextBox;
                    if (mailList != null)
                    {
                        String mailList2Format = mailList.Text;
                        mailList.Text = mailList2Format.Replace(';', '\n');
                    }

                    //handle rule controls on modifying
                    LinkButton ruleModifier = row.FindControl(RULE_BUTTON_ID) as LinkButton;
                    Label ruleDisplayOnModify = row.FindControl(RULE_MODIFY_LABEL_ID) as Label;

                    //get the editing method
                    String editingMethod = Session[SESSION_EDITING_METHOD] as String;
                    
                    //enable editing rule only on adding
                    ruleModifier.Visible = editingMethod.Equals(ADD_METHOD);
                    ruleDisplayOnModify.Text = expressionBuilder.getRuleString();
                    ruleDisplayOnModify.Visible = editingMethod.Equals(MODIFY_METHOD);

                    //disable name editing on modifying
                    TextBox validationNameBox = row.FindControl(NAME_TEXTBOX_ID) as TextBox;
                    validationNameBox.Visible = editingMethod.Equals(ADD_METHOD);
                    Label nameDisplayOnModify = row.FindControl(NAME_MODIFY_LABEL_ID) as Label;
                    nameDisplayOnModify.Visible = editingMethod.Equals(MODIFY_METHOD);
                }
                else
                {
                    //handle applied on Default column
                    Label appliedLabel = (Label)row.FindControl(APPLIED_LABEL_ID);
                    if (appliedLabel != null)
                    {
                        appliedLabel.Text =
                            appliedLabel.Text.ToLower().Equals("false") ? "No" : "Yes";
                        appliedLabel.ForeColor =
                            appliedLabel.Text.Equals("No") ? Color.Red : Color.Green;
                    }
                }
            }
        }

        #endregion

        #region Helpers:

        /// <summary>
        /// Create a trigger for an AJAX UpdatePanel
        /// </summary>
        /// <param name="panel">The UpdatePanel server object</param>
        /// <param name="control">The triggering control</param>
        /// <param name="eventName">The triggering control's event</param>
        private void setButtonAsTrigger(UpdatePanel panel, Control control, String eventName)
        {
            AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
            trigger.ControlID = control.ClientID;
            trigger.EventName = eventName;
            panel.Triggers.Add(trigger);
        }

        /// <summary>
        /// Set triggers from the DataGrid selected row to the ExpressionBuilder UpdatePanel
        /// </summary>
        /// <param name="selectedRow">The selected row containing the triggering controls</param>
        private void setExpressionBuilderDataGridTriggers(GridViewRow selectedRow)
        {
            LinkButton createRuleButton = selectedRow.FindControl(RULE_BUTTON_ID) as LinkButton;
            Button saveButton = selectedRow.FindControl(SAVE_ROW_BUTTON) as Button;
            Button cancelButton = selectedRow.FindControl(CANCEL_ROW_BUTTON) as Button;
        }

        /// <summary>
        /// Parse the mail list out of the textbox in UI
        /// </summary>
        /// <param name="textBoxString"></param>
        /// <returns></returns>
        private String[] getMailList(String textBoxString)
        {
            return textBoxString.Split(
                new char[] { '\r', '\n' }, 
                StringSplitOptions.RemoveEmptyEntries);
        }

        /// <summary>
        /// Make all dataGrid's columns visible
        /// </summary>
        private void DisplayAllGridColumns()
        {
            foreach (DataControlField column in dataGridView.Columns)
                column.Visible = true;
        }

        /// <summary>
        /// Save the columns selected by the user to be displayed. used on editing or adding new row
        /// </summary>
        private void SaveColumnsSelection()
        {
            IList<String> visibleColumns = new List<String>();

            foreach (DataControlField column in dataGridView.Columns)
            {
                if (column.Visible)
                    visibleColumns.Add(column.HeaderText);
            }

            Session[SESSION_COLUMNS_LIST] = visibleColumns;
        }

        /// <summary>
        /// Restore the columns selected by the user to be displayed. used after finishing editing or adding new row
        /// </summary>
        private void RestoreColumnsSelection()
        {
            IList<String> visibleColumns = 
                Session[SESSION_COLUMNS_LIST] as IList<String>;

            foreach (DataControlField column in dataGridView.Columns)
            {
                column.Visible = visibleColumns.Contains(column.HeaderText);
            }
        }

        private void DisableFilterPane()
        {
            filterButton.Text = "Confirm";
            filterButton.ToolTip = "Open columns filter pane";
        }

        #endregion

        #region AbstractPage Implementation:

        /// <see cref="Danser_AJAXEnabledWebApplication.AbstractPage.InnerValidatePermission"/>
        protected override bool InnerValidatePermission(PermissionLevel permissionlevel)
        {
            return permissionlevel == PermissionLevel.Admin || permissionlevel == PermissionLevel.Manager;
        }

        #endregion

    }


}
